#pragma once

#include "Stimulus.h"
#include "IStimulus.h"

namespace SpikingNeuronLib
{
	// An input stimulus where the stimulus can change each second
	// Each stimulus consists of a pattern that is presented one or more times per second
	public ref class MultiStimulus : public IStimulus
	{
	protected:
		bool _isEmpty;										// true if there are no firing events in the stimulus
		array<array<array<int>^>^>^ _stimulusFiringData;	// the neurons that fire in each one msec timeslot (arranged by stimulus, msec)
		array<int>^ _sequence;								// the sequence order for the stimuli (one stimulus per second)
		List<Stimulus^>^ _sourceStimuli;					// the original source stimuli

		// Get the correct stimlus for the specified second
		inline int GetStimulusIndex(int second)
		{
			int index = second % _sequence->Length;		// retrieve the sequence slot
			return _sequence[index];					// retrieve the current stimulus
		}

	public:
		MultiStimulus(System::Collections::Generic::IEnumerable<Stimulus^>^ stimuli, array<int>^ sequence);

		property List<Stimulus^>^ SourceStimuli
		{
			List<Stimulus^>^ get() { return _sourceStimuli; }
		}

		// IStimlus implementation -------------------------------------------------------------------------------------------

		// Returns true if the stimulus has no events
		virtual property bool IsEmpty
		{
			bool get() { return _isEmpty; }
		}

		virtual property HashSet<int>^ PatternNeurons
		{
		public:
			HashSet<int>^ get()
			{
				HashSet<int>^ patternNeurons = gcnew HashSet<int>();
				for each (Stimulus^ stimulus in _sourceStimuli)
				{
					patternNeurons->UnionWith(stimulus->PatternNeurons);
				}

				return patternNeurons;
			}
		}

		// Returns the neuron firing data for the specified second
		// A list of firing neurons for each one msec timeslot
		virtual array<array<int>^>^ GetNeuronFiringData(int second);

		// Returns true if there are neurons that fire in the specified one msec timeslot
		virtual bool FiresAtTime(int second, int millisecond);

		// Returns the list of neurons that fire in the specified one msec timeslot
		virtual array<int>^ GetFiringNeurons(int second, int millisecond);

		// -------------------------------------------------------------------------------------------

	};
}
